/*
 * Copyright (c) 2022, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "atom.h"
#include "pwm.h"
#include "console.h"
#include "debug.h"
#include "syslog.h"
#include <string.h>
#include "numberical.h"

static enConsoleResult pwm_cmd(int argc, char** argv)
{
	FD fd = open("pwm", 0, 0);
	Pwm* pwm = (Pwm*)fd;
	enConsoleResult ret = CE_OK;
	int result = NG;

	if (argc >= 3) {
		if (pwm != NULL) {
			if (strcmp(argv[1], "enable") == 0 && argc == 3) {
				int channel = (int)StringToInt(argv[2]);
				result = PwmEnable(pwm, channel);
			}
			else if (strcmp(argv[1], "disable") == 0 && argc == 3) {
				int channel = (int)StringToInt(argv[2]);
				result = PwmDisable(pwm, channel);
			}
			else if (strcmp(argv[1], "set") == 0 && argc == 5) {
				int channel = (int)StringToInt(argv[2]);
				int period = (int)StringToInt(argv[3]);
				int pulse = (int)StringToInt(argv[4]);
				result = PwmSet(pwm, channel, period, pulse);
			}
			else {
				KPrint("pwm [enable|disable|set] [channel] [period] [pulse]\r\n");
			}

			if (result != 0) ret = CE_RUNTIME_ERROR;

			close(fd);
		}
		else {
			SYSLOG(LOG_ERR, "no device found!");
		}
	}
	else {
		KPrint("pwm [enable|disable|set] [channel] [period] [pulse]\r\n");
	}

	return ret;
}

BGEIN_DEF_CMD(_pwmCmd)
	CMD_DEF_ALISA(pwm, pwm_cmd, "pwm [enable|disable|set] [channel] [period] [pulse]")
END_DEF_CMD(_pwmCmd)

void PwmCreate(Pwm *pwm, PFIOCTL ioctl)
{
    pwm->super.popen = NULL;
    pwm->super.pioctl = ioctl;
    pwm->super.pread = NULL;
    pwm->super.pwrite = NULL;
    pwm->super.pclose = NULL;

    IosDrvInstall(&pwm->super, "pwm");
#if defined(BSP_USE_PWM) && defined(COM_USE_PWM_CMD)    
    CONSOLE_REG_CMD(_pwmCmd);
#endif 
}

int PwmSet(Pwm* pwm, int channel, int period, int pulse)
{
    PwmIoctlSet set = { channel, period, pulse };

    if (pwm->super.pioctl != NULL) {
        return pwm->super.pioctl((FD)pwm, IOCTL_PWM_SET, &set);
    }

    return NG;
}

static int pwm_set_state(Pwm* pwm, int channel, int enable)
{
    PwmIoctlState set = { channel, enable };

    if (pwm->super.pioctl != NULL) {
        return pwm->super.pioctl((FD)pwm, IOCTL_PWM_ENABLE, &set);
    }

    return NG;
}


int PwmEnable(Pwm* pwm, int channel)
{
    return pwm_set_state(pwm, channel, 1);
}


int PwmDisable(Pwm* pwm, int channel)
{
    return pwm_set_state(pwm, channel, 0);
}